from time import sleep
from selenium.common import exceptions as SeleniumExceptions
from selenium.webdriver.common.keys import Keys

from qturboframe.lib.utils.CustomError.custom_error import CustomError
from qturboframe.lib.utils.CustomError.custom_exception import CustomException
from qturboframe.lib.report.log import logger
from qturboframe.lib.webdriver.exceptions import SeleniumError
from qturboframe.lib.webdriver.remote.webelement import WebElement
from qturboframe.lib.utils.__datatime_format__ import split_datetime, split_time
from qturboframe.lib.utils.check import CheckBasic
from qturboframe.public_ui.base_element import BaseElement
from qturboframe.public_ui.h_ui.button import Button


class Calendar(BaseElement, CheckBasic):
    """
    hui的日历控件操作

    :Attributes:
     - calendar_div: 日历控件的弹出框div元素
    """

    calendar_div = WebElement

    def __init__(self, element_para, father=None, timeout=5):
        super().__init__(element_para, father, timeout)
        class_list = self._element.get_attribute('class').split(' ')
        if 'h-date-picker' not in class_list:
            xpath_1 = './ancestor::div[@class="h-date-picker"]'
            xpath_2 = './ancestor::div[contains(@class,"canEdit") and contains(@class,"h-date-picker") ]'
            xpath = xpath_1 + " | " + xpath_2
            self._element = self._element.find_element_by_attribute(
                'xpath', xpath, timeout=self.timeout)

    def set_value(self, value):
        """
        hui日历控件赋值

        :Args:
         - value: 日期值或者日期范围

        :Usage:
         - calendar.set_value('20200420')
         - calendar.set_value('20200420 - 20200520')
        """
        # 数据驱动选项
        text_list = value.split(' - ')
        if len(text_list) == 1:
            self.set_value_for_single(text_list[0])
        elif len(text_list) == 2:
            self.set_value_for_range(text_list[0], text_list[1])
        else:
            message = '日期参数格式不规范！'
            raise CustomException(CustomError.Error_EQ03008001_Parameter_InCorrect, message)

    def set_value_for_single(self, value):
        """
        hui日历组件赋值

        :Args:
         - value: 日期值

        :Usage:
         - calendar.set_value_for_single('20200420')
         - calendar.set_value_for_single('2020/04/20')
         - calendar.set_value_for_single('2020-04-20')
        """
        re_displaynone = 'display: none;'
        calendar_input = self._element.find_element_by_attribute('tag name', 'input', timeout=self.timeout)
        calendar_input.secure_click()
        self.calendar_div = self._element.exist(
            'css selector', 'div.h-select-dropdown', timeout=0.1)
        if not self.calendar_div:
            # self.calendar_div = self._driver.find_element_by_attribute(
            #     'css selector', 'body>div.h-select-dropdown', 'style:display: block;', timeout=self.timeout)
            self.calendar_div = self._driver.find_element_by_attribute(
                'xpath', "//body/div[contains(@class,'h-select-dropdown') and not(contains(@style,'display: none'))]",
                timeout=self.timeout)
        # 数据处理
        text_list = value.split(' ')
        if len(text_list) == 1:
            date_text = text_list[0]
            time_text = None
        elif len(text_list) == 2:
            date_text = text_list[0]
            time_text = text_list[1]
        else:
            message = '日期时间参数不符合日期规范！！'
            raise CustomException(CustomError.Error_EQ03008001_Parameter_InCorrect, message)
        year, month, day = split_datetime(date_text)
        # 选择year
        div_style = self.calendar_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_year(year)
        # 选择month
        div_style = self.calendar_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_month(month)
        # 选择day
        div_style = self.calendar_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_day(day)
        # 选择时间
        if time_text:
            hour, minute, second = split_time(time_text)
            # 选择hour
            div_style = self.calendar_div.get_attribute('style')
            time_span_btn = self.calendar_div.find_element_by_attribute(
                'css selector', 'div.h-picker-confirm>span', 'text:选择时间', timeout=0.1)
            time_span_btn.secure_click()
            if re_displaynone not in div_style:
                self.__set_hour(hour)
            # 选择minute
            div_style = self.calendar_div.get_attribute('style')
            if re_displaynone not in div_style:
                self.__set_minute(minute)
            # 选择second
            div_style = self.calendar_div.get_attribute('style')
            if re_displaynone not in div_style:
                self.__set_second(second)
        # 确定
        div_style = self.calendar_div.get_attribute('style')
        if re_displaynone not in div_style:
            confirm_div = self.calendar_div.exist('css selector', 'div.h-picker-confirm', timeout=0.1)
            if confirm_div:
                try:
                    Button({'css selector': 'button.h-btn', 'text': '确定'}, confirm_div, 0.1).click()
                except:
                    calendar_input.send_keys(Keys.ESCAPE)
            else:
                calendar_input.send_keys(Keys.ESCAPE)

    def set_value_for_range(self, value1, value2):
        """
        hui日历范围组件赋值

        :Args:
         - value: 日期值

        :Usage:
         - calendar.set_value_for_range('20200420 - 20200520')
         - calendar.set_value_for_range('2020/04/20 - 2020/05/20')
        """
        re_displaynone = 'display: none;'
        calendar_input = self._element.find_element_by_attribute('tag name', 'input', timeout=self.timeout)
        calendar_input.secure_click()
        self.calendar_div = self._element.exist(
            'css selector', 'div.h-select-dropdown', timeout=0.1)
        if not self.calendar_div:
            # self.calendar_div = self._driver.find_element_by_attribute(
            #     'css selector', 'body>div.h-select-dropdown', 'style:display: block;', timeout=self.timeout)
            self.calendar_div = self._driver.find_element_by_attribute(
                'xpath', "//body/div[contains(@class,'h-select-dropdown') and not(contains(@style,'display: none'))]",
                timeout=self.timeout)
        calendar_div_left = self.calendar_div.find_element_by_attribute(
            'css selector',
            'div.h-date-picker-with-range>div.h-picker-panel-body>div.h-picker-panel-content-left',
            timeout=self.timeout)
        calendar_div_right = self.calendar_div.find_element_by_attribute(
            'css selector',
            'div.h-date-picker-with-range>div.h-picker-panel-body>div.h-picker-panel-content-right',
            timeout=self.timeout)
        # 数据处理
        text_list1 = value1.split(' ')
        if len(text_list1) == 1:
            date_text1 = text_list1[0]
            time_text1 = None
        elif len(text_list1) == 2:
            date_text1 = text_list1[0]
            time_text1 = text_list1[1]
        else:
            message = '日期时间参数不符合日期规范！！'
            raise CustomException(CustomError.Error_EQ03008001_Parameter_InCorrect, message)
        year1, month1, day1 = split_datetime(date_text1)
        text_list2 = value2.split(' ')
        if len(text_list2) == 1:
            date_text2 = text_list2[0]
            time_text2 = None
        elif len(text_list2) == 2:
            date_text2 = text_list2[0]
            time_text2 = text_list2[1]
        else:
            message = '日期时间参数不符合日期规范！！'
            raise CustomException(CustomError.Error_EQ03008001_Parameter_InCorrect, message)
        year2, month2, day2 = split_datetime(date_text2)
        temp_div = self.calendar_div
        self.calendar_div = calendar_div_left
        # 选择year1
        div_style = temp_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_year(year1)
        # 选择month1
        div_style = temp_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_month(month1)
        # 选择day1
        div_style = temp_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_day(day1)
        self.calendar_div = calendar_div_right
        # 选择year2
        div_style = temp_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_year(year2)
        # 选择month2
        div_style = temp_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_month(month2)
        # 选择day2
        div_style = temp_div.get_attribute('style')
        if re_displaynone not in div_style:
            self.__set_day(day2)
        # 选择时间1
        if time_text1:
            hour, minute, second = split_time(time_text1)
            # 选择hour
            div_style = temp_div.get_attribute('style')
            time_span_btn = temp_div.find_element_by_attribute(
                'css selector', 'div.h-picker-confirm>span', 'text:选择时间', timeout=0.1)
            time_span_btn.secure_click()
            time_div_left = temp_div.find_element_by_attribute(
                'css selector',
                'div.h-time-picker-with-range>div.h-picker-panel-body>div.h-picker-panel-content-left',
                timeout=self.timeout)
            self.calendar_div = time_div_left
            if re_displaynone not in div_style:
                self.__set_hour(hour)
            # 选择minute
            div_style = temp_div.get_attribute('style')
            if re_displaynone not in div_style:
                self.__set_minute(minute)
            # 选择second
            div_style = temp_div.get_attribute('style')
            if re_displaynone not in div_style:
                self.__set_second(second)
        # 选择时间2
        if time_text2:
            hour, minute, second = split_time(time_text2)
            time_div_right = temp_div.find_element_by_attribute(
                'css selector',
                'div.h-time-picker-with-range>div.h-picker-panel-body>div.h-picker-panel-content-right',
                timeout=self.timeout)
            self.calendar_div = time_div_right
            # 选择hour
            div_style = temp_div.get_attribute('style')
            if re_displaynone not in div_style:
                self.__set_hour(hour)
            # 选择minute
            div_style = self.calendar_div.get_attribute('style')
            if re_displaynone not in div_style:
                self.__set_minute(minute)
            # 选择second
            div_style = self.calendar_div.get_attribute('style')
            if re_displaynone not in div_style:
                self.__set_second(second)
        # 确定
        div_style = temp_div.get_attribute('style')
        if re_displaynone not in div_style:
            confirm_div = temp_div.exist('css selector', 'div.h-picker-confirm', timeout=0.1)
            if confirm_div:
                Button({'css selector': 'button.h-btn', 'text': '确定'}, confirm_div, 0.1).js_click()
            else:
                calendar_input.send_keys(Keys.ESCAPE)

    def __set_year(self, year):
        head_div = self.calendar_div.find_element_by_attribute(
            'css selector', 'div.h-date-picker-header', timeout=self.timeout)
        year_span_button = head_div.find_elements_by_attribute(
                'css selector', 'span.h-date-picker-header-label', timeout=self.timeout)[0]
        year_span_button.secure_click()
        year_div = self.calendar_div.find_element_by_attribute(
            'css selector', 'div.h-date-picker-cells-year', timeout=self.timeout)
        year_spans = year_div.find_elements_by_attribute('xpath', './span', timeout=self.timeout)
        if int(year_spans[0].text) > int(year):
            year_prev_button = head_div.find_element_by_attribute(
                'css selector', 'span.h-date-picker-prev-btn', timeout=self.timeout)
            year_prev_button.secure_click()
            self.__set_year(year)
        elif int(year_spans[-1].text) < int(year):
            year_next_button = head_div.find_element_by_attribute(
                'css selector', 'span.h-date-picker-next-btn', timeout=self.timeout)
            year_next_button.secure_click()
            self.__set_year(year)
        else:
            for year_span in year_spans:
                while 1==1:
                    try:
                        year_text = year_span.text
                        break
                    except SeleniumExceptions.StaleElementReferenceException:
                        sleep(0.1)
                try:
                    year_int = int(year_text)
                except:
                    continue
                if year_int == int(year):
                    year_span.secure_click()
                    break

    def __set_month(self, month):
        month_div = self.calendar_div.find_element_by_attribute(
            'css selector', 'div.h-date-picker-cells-month', timeout=self.timeout)
        month_spans = month_div.find_elements_by_attribute('tag name', 'span', timeout=self.timeout)
        month_spans[int(month) - 1].secure_click()

    def __set_day(self, day):
        re_old = r'h-date-picker-cells-cell-prev-month'
        re_new = r'h-date-picker-cells-cell-next-month'
        day_div = self.calendar_div.find_element_by_attribute(
            'css selector', 'div.h-date-picker-cells', timeout=self.timeout)
        day_ems = day_div.find_elements_by_attribute(
            'xpath', './span/em[text()="{}"]'.format(int(day)), timeout=self.timeout)
        for day_em in day_ems:
            day_span = day_em.find_element_by_attribute('xpath', './parent::span', timeout=self.timeout)
            day_span_class_list = day_span.get_attribute('class').split(' ')
            if re_old not in day_span_class_list and re_new not in day_span_class_list:
                day_span.secure_click()
                break

    def __set_hour(self, hour):
        re_displaynone = 'display: none;'
        head_div = self.calendar_div.find_elements_by_attribute(
            'css selector', 'div.h-time-picker-cells>div.h-time-picker-cells-list', timeout=self.timeout)[0]
        div_style = head_div.get_attribute('style')
        if re_displaynone not in div_style:
            hour_li = head_div.find_elements_by_attribute(
                    'css selector', 'ul.h-time-picker-cells-ul>li.h-time-picker-cells-cell',
                timeout=self.timeout)[int(hour)]
            hour_li.focus()
            hour_li.secure_click()

    def __set_minute(self, minute):
        re_displaynone = 'display: none;'
        head_div = self.calendar_div.find_elements_by_attribute(
            'css selector', 'div.h-time-picker-cells>div.h-time-picker-cells-list', timeout=self.timeout)[1]
        div_style = head_div.get_attribute('style')
        if re_displaynone not in div_style:
            minute_li = head_div.find_elements_by_attribute(
                'css selector', 'ul.h-time-picker-cells-ul>li.h-time-picker-cells-cell',
                timeout=self.timeout)[int(minute)]
            minute_li.focus()
            minute_li.secure_click()

    def __set_second(self, second):
        re_displaynone = 'display: none;'
        head_div = self.calendar_div.find_elements_by_attribute(
            'css selector', 'div.h-time-picker-cells>div.h-time-picker-cells-list', timeout=self.timeout)[2]
        div_style = head_div.get_attribute('style')
        if re_displaynone not in div_style:
            second_li = head_div.find_elements_by_attribute(
                'css selector', 'ul.h-time-picker-cells-ul>li.h-time-picker-cells-cell',
                timeout=self.timeout)[int(second)]
            second_li.focus()
            second_li.secure_click()

    def clear(self):
        """
        hui日历控件值清除选项值

        :Example:
         - 例: calendar.clear()
        """
        self._element.move_to()
        if self._element.exist('css selector', 'div.h-select-selection>i.h-icon-close',
                     timeout=self.timeout):
            self._element.find_element_by_attribute(
                'css selector', 'div.h-date-picker-editor>i.h-icon-close',
                timeout=self.timeout).secure_click()
        else:
            message = '没有清除按钮，无法删除！'
            raise SeleniumError(CustomError.Error_EQ03001000_Cannot_Find_Element, message)

    def is_default(self, value):
        """
        检查hui日历控件默认值

        :Args:
         - value: 待检查的选项值

        :Returns:
            匹配返回True，否则返回False

        :Example:
         - 例1: calendar.is_default('20200420')
         - 例2: calendar.is_default('2020/04/20')
         - 例3calendar.is_default('2020-04-20')
        """
        inputele = self._element.find_element_by_attribute('tag name', 'input', timeout=self.timeout)
        inputele.focus()
        if inputele.get_attribute('value'):
            text = inputele.get_attribute('value')
        elif inputele.get_attribute('placeholder'):
            text = inputele.get_attribute('placeholder')
        elif inputele.get_attribute('defaultValue'):
            text = inputele.get_attribute('defaultValue')
        else:
            text = ''
        if text:
            if text == value:
                return True
            else:
                logger.error('默认值不匹配！')
                return False
        else:
            logger.error('没有默认值！')
            return False

    def is_nonnull(self):
        '''
        检查hui日历控件是否有非空属性

        :Returns:
            非空返回True，否则返回False

        :Example:
         - 例: calendar.is_nonnull()
        '''
        self._element.focus()
        form_item = self._element.find_element_by_attribute(
            'xpath', './ancestor::div[contains(@class, "h-form-item-content")]/'
                     'parent::div[contains(@class, "h-form-item")]', timeout=self.timeout)
        item_class_list = form_item.get_attribute('class').split(' ')
        if 'h-form-item-required' in item_class_list:
            return True
        else:
            return False

    def check_default(self, value):
        '''
        校验hui日历控件默认值

        :Args:
         - value: 待检查的选项值

        :Raises:
            SeleniumError: 日历控件默认值校验不通过

        :Example:
         - 例1: calendar.check_default('20200420')
         - 例2: calendar.check_default('2020/04/20')
         - 例3: calendar.check_default('2020-04-20')
        '''
        if not self.is_default(value):
            message = '日历控件默认值校验不通过！'
            raise SeleniumError(CustomError.Error_EQ03011001_Calendar_Default_Data_InCorrect, message)

    def check_nonull(self):
        '''
        校验hui日历控件是否非空

        :Raises:
            SeleniumError: 日历控件非空校验不通过

        :Example:
         - 例: calendar.check_nonull()
        '''
        if not self.is_nonnull():
            message = '日历控件非空校验不通过！'
            raise SeleniumError(CustomError.Error_EQ03011001_Calendar_Not_Default_Data_InCorrect, message)
